//
// Created by wyh on 2025-06-16 19:47.
//
#include <sstream>
#include <synchapi.h>
#include <cstdarg>
#include <iostream>
#include "utility/logger.h"

using namespace std;
using namespace wyh::utility;

const char* Logger::s_leval[LOG_COUNT] = {
        "DEBUG","INFO","WARN","ERROR","FATAL"
};

void Logger::open(const std::string &filename)
{
    m_filename = filename;
    m_ofs.open(filename, ios::app);
    if (m_ofs.fail())
    {
        throw logic_error("open log file failed:" + filename);
    }

    m_ofs.seekp(0, ios::end);
    m_len = (int) m_ofs.tellp();
}

void Logger::close()
{
    m_ofs.close();
}

void Logger::log(Logger::Leval leval, const char *file, int line, const char *format, ...)
{
    if(m_leval > leval)
    {
        return;
    }

    if (m_ofs.fail())
    {
        return;
    }

    ostringstream oss;
    time_t ticks = time(nullptr);
    struct tm time_info = {0};
    localtime(&time_info, &ticks);

    char timestamp[32] = {0};
    strftime(timestamp, sizeof(timestamp), "%Y-%m-%d %H:%M:%S", &time_info);

    //    cout << "时间戳= " << ticks << "--年月日：" << timestamp << endl;
    int len = 0;
    const char *fmt = "%s %s %s:%d ";
    len = snprintf(nullptr, 0, fmt, timestamp, s_leval[leval], file, line);
    if (len > 0)
    {
        char *buffer = new char[len + 1];
        snprintf(buffer, len + 1, fmt, timestamp, s_leval[leval], file, line);
        buffer[len] = '\0';
        oss << buffer;
        m_len += len;
        delete[] buffer;
    }

    va_list arg_ptr;
    va_start(arg_ptr,format);
    len = vsnprintf(nullptr, 0, format, arg_ptr);
    va_end(arg_ptr);
    if (len > 0)
    {
        char *content = new char[len + 1];
        va_start(arg_ptr,format);
        vsnprintf(content, len + 1, format, arg_ptr);
        va_end(arg_ptr);
        content[len] = 0;
        oss<<content;
        m_len += len;
        delete[] content;
    }
    oss<<'\n';

    const string &str = oss.str();

    unique_lock<mutex> lck(m_mutex);// lck 析构时自动解锁
    m_ofs<<str;
    m_ofs.flush();

    if (m_console)
    {
        cout<<str;
    }

    if (m_max > 0 && m_len > m_max)
    {
        //日志需要翻滚
        rotate();
    }
}

void Logger::rotate()
{
    close();
    sleep(1000);

    time_t ticks = time(nullptr);
    struct tm time_info={0};
    localtime(&time_info, &ticks);
    char timestamp[32] = {0};
    strftime(timestamp, sizeof(timestamp), ".%Y-%m-%d_%H-%M-%S", &time_info);

    string filename = m_filename + timestamp;
    if (rename(m_filename.c_str(), filename.c_str()) != 0)
    {
        throw logic_error("rename log file failed");
    }
    open(m_filename);
}

void Logger::localtime(struct tm *time_info, const time_t *ticks)
{
#ifdef _WIN32
    localtime_s(time_info, ticks);
#else
    localtime_r(ticks,time_info);
#endif
}

void Logger::sleep(int milliseconds)
{
#ifdef _WIN32
    Sleep(milliseconds);
#else
    std::this_thread::sleep_for(std::chrono::milliseconds(milliseconds));
#endif
}

void Logger::set_leval(Logger::Leval leval)
{
    m_leval = leval;
}

void Logger::set_max_size(int size)
{
    m_max = size;
}

void Logger::set_console(bool console)
{
    m_console = console;
}
